#include <LBP.h>

////////////////////////////////////////////////////////////////////////////////
LBP::LBP()
{
	image.release();
	hist.release();
	neighbourhood.clear();
	w=NULL;
	this->r=0;
	this->p=0;
}
////////////////////////////////////////////////////////////////////////////////
LBP::LBP(int r, int p)
{
	image.release();
	hist.release();
	neighbourhood.clear();
	w=NULL;

	if(p>30)
	{
		std::cout<<"Erreur LBP : Impossible de calculer le LBP p>30\n"; 
		return;
	}
	w=new long[p];
	for(int i=0;i<p;i++)w[i]=1<<i;	

	float step=2.0*M_PI/p;
	int i=0;
	float angle=0.0;
	for(;i<p;i++,angle+=step)
	{
		cv::Point new_pt(round(r*cos(angle)),round(r*sin(angle)));
		neighbourhood.push_back(new_pt);
	}
	this->r=r;
	this->p=p;
}
////////////////////////////////////////////////////////////////////////////////
LBP::LBP(cv::Mat & img,int r, int p)
{
	setImage(img);
	hist.release();
	neighbourhood.clear();
	w=NULL;

	if(p>30)
	{
		std::cout<<"Erreur LBP : Impossible de calculer le LBP p>30\n"; 
		return;
	}
	w=new long[p];
	for(int i=0;i<p;i++)w[i]=1<<i;	

	float step=2.0*M_PI/p;
	int i=0;
	float angle=0.0;
	for(;i<p;i++,angle+=step)
	{
		cv::Point new_pt(round(r*cos(angle)),round(r*sin(angle)));
		neighbourhood.push_back(new_pt);
	}
	this->r=r;
	this->p=p;
}
////////////////////////////////////////////////////////////////////////////////
void LBP::create(int r, int p)
{
	image.release();
	hist.release();
	neighbourhood.clear();

	if(p>30)
	{
		std::cout<<"Erreur LBP : Impossible de calculer le LBP p>30\n";
		return;
	}
	if(w!=NULL)delete [] w;
	w=new long[p];
	for(int i=0;i<p;i++)w[i]=1<<i;	

	float step=2.0*M_PI/p;
	int i=0;
	float angle=0.0;
	for(;i<p;i++,angle+=step)
	{
		cv::Point new_pt(round(r*cos(angle)),round(r*sin(angle)));
		neighbourhood.push_back(new_pt);
	}
	this->r=r;
	this->p=p;
}
////////////////////////////////////////////////////////////////////////////////
void LBP::create(cv::Mat & img,int r, int p)
{
	setImage(img);
	hist.release();
	neighbourhood.clear();
	
	if(p>30)
	{
		std::cout<<"Erreur LBP : Impossible de calculer le LBP p>30\n"; 
		return;
	}
	if(w!=NULL)delete [] w;
	w=new long[p];
	for(int i=0;i<p;i++)w[i]=1<<i;	

	float step=2.0*M_PI/p;
	int i=0;
	float angle=0.0;
	for(;i<p;i++,angle+=step)
	{
		cv::Point new_pt(round(r*cos(angle)),round(r*sin(angle)));
		neighbourhood.push_back(new_pt);
	}
	this->r=r;
	this->p=p;
}
////////////////////////////////////////////////////////////////////////////////
void LBP::setImage(cv::Mat & img)
{
	if(img.channels()==1)
	{
		if(img.depth()==CV_8U)
		{
			image=img.clone();
		}
		else
		{
			std::cout<<"Erreur LBP : img.depth()!=CV_8U\n";
			image.release();
		}
	}
	else
	{
		std::cout<<"Erreur LBP : img.channels()!=1\n";
		image.release();
	}
}
////////////////////////////////////////////////////////////////////////////////
int LBP::getLBP(int row,int col)
{
	if(!image.empty())
	{
		int lbp=0;
		for(unsigned int i=0;i<neighbourhood.size();i++)
		{
			lbp+=w[i]*(image.at<unsigned char>(row+neighbourhood[i].y,col+neighbourhood[i].x) > image.at<unsigned char>(row,col));
		}
		return lbp;
	}
	else
	{
		return -1;
	}
}
////////////////////////////////////////////////////////////////////////////////
void LBP::getHist(cv::Mat & histLBP)
{
	cv::Mat_<float> h(1<<p,1);
	h.setTo(0.0);

	for(int i=r;i<image.rows-r;i++)
	{
		for(int j=r;j<image.cols-r;j++)
		{
			h(getLBP(i,j))+=1.0;
		}
	}
	
	h/=(image.rows*image.cols);

	histLBP=h.clone();
}

////////////////////////////////////////////////////////////////////////////////
void LBP::getUniformHist(cv::Mat & histLBP)
{
	cv::Mat_<float> hu(p*p-p+1,1);
	hu.setTo(0.0);
	
	cv::Mat_<float> h;
	getHist(h);
	
	int j=0;
	for(int i=0;i<h.rows;i++)
	{
		if(isUniform(i))
		{
			//printf("%d %d\n",i,j);
			hu(j++)=h(i);
		}
	}
	histLBP=hu.clone();
}
////////////////////////////////////////////////////////////////////////////////
bool LBP::isUniform(int lbp)
{
	int count=0;	
	int N=lbp;
	bool Digit=N & 1;

	int i=p-1;
	while((i--)>0)
	{
		N=N>>1;
		if((N & 1)!=Digit)
		{
			Digit=N & 1;
			count++;
		}
	}

	if(count<=2)
	{
		return true;
	}
	else
	{
		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
